package com.wongoing.sys.shiro;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.wongoing.sys.model.SysPermission;
import com.wongoing.sys.model.SysUser;
import com.wongoing.sys.service.SysPermissionService;
import com.wongoing.sys.service.SysUserService;
import com.wongoing.util.Constants;
import com.wongoing.util.LogService;
import com.wongoing.util.LoginType;
import com.wongoing.util.SubjectUtil;

@Component
public class ShiroUserRealm extends AuthorizingRealm {

	private SysUserService sysUserService;
	private SysPermissionService sysPermissionService;

	@Autowired
	public void setSysUserService(SysUserService sysUserService) {
		this.sysUserService = sysUserService;
	}
	
	@Autowired
	public void setSysPermissionService(SysPermissionService sysPermissionService) {
		this.sysPermissionService = sysPermissionService;
	}

	/**
	 * 获取认证信息
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken at) throws AuthenticationException {
		//1、把AuthenticationToken转换为UsernamePasswordToken
		//UsernamePasswordToken token = (UsernamePasswordToken)at;
		ShiroUserTypeUsernamePasswordToken token = (ShiroUserTypeUsernamePasswordToken)at;
		//2、从UsernamePasswordToken中获取用户名（实际为表单提交的用户名）
		String username = token.getUsername();
		//3、判断用户名是否为空
		if (username != null && !"".equals(username))
		{
			Map<String, Object> param = new HashMap<String, Object>();
			param.put("status", Constants.PERSISTENCE_ENABLE_STATUS);
			param.put("account", username);
			try
			{
				List<SysUser> users = this.sysUserService.getByParam(param);
				//判断数据库用户表中是否存在此用户
				if (users != null && !users.isEmpty())
				{
					SysUser sysUser = users.get(0);
					ShiroUser shiroUser = new ShiroUser(sysUser.getId(), sysUser.getAccount(),LoginType.USER.getTypeEn());
					Subject subject = SecurityUtils.getSubject();
					subject.getSession().setAttribute(SubjectUtil.SHIRO_USER, shiroUser);
					//获取系统权限项
					List<SysPermission> perList = null;
					if (Constants.SYSTEM_USER.equals(username)) {
						perList = this.sysPermissionService.getByStatusAndType(Constants.PERSISTENCE_ENABLE_STATUS, "F"); 
					}
					else {
						perList = this.sysPermissionService.getByUserAccount(username, Constants.PERSISTENCE_ENABLE_STATUS, "F");
					}
					subject.getSession().setAttribute("SystemMenus", perList);		//在Session中缓存系统菜单
					for (SysPermission sysPermission : perList) {
						System.out.println(sysPermission.getName()+"||"+sysPermission.getUrl());
					}
					//4、根据用户的情况，来构建AuthenticationInfo对象并返回，通常使用的实现类为SimpleAuthenticationInfo
					//整理信息
					//（1）principal：认证的实体信息，可以是用户实体对象，也可以是能够标识用户的用户名或邮箱手机号，此处使用shiroUser对象
					Object principal = shiroUser;
					//（2）credentials：加密后的密码
					Object credentials = sysUser.getPassword(); // "81b25688e81c08aeee9cd422866b1b2ac41e4d80"
					//（3）realmName：当前realm对象的name，调用父类的getName()方法即可
					String realName = super.getName();
					//（4）盐值：取用户信息中唯一的字段来生成盐值，避免由于两个用户原始密码相同，加密后的密码也相同
					ByteSource credentialSalt = ByteSource.Util.bytes(username + ShiroHelper.SALT2);
					
					SimpleAuthenticationInfo sai = new SimpleAuthenticationInfo(principal, credentials, credentialSalt, realName);
					LogService.getInstance(this).debug(username + "获取认证信息成功...");
					return sai;
				}
				else
				{
					LogService.getInstance(this).error("后台用户【" + username + "】在用户表中不存在!");
					return null;
				}
			}
			catch(Exception ex)
			{
				LogService.getInstance(this).error(username + "获取认证信息失败：" + ex.getMessage(), ex);
				return null;
			}
		}
		return null;
	}
	
	/**
	 * 获取授权信息
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
		if(pc == null || pc.isEmpty()) {System.out.println("这是一个null集合......");}
		ShiroUser shiroUser = (ShiroUser)pc.fromRealm(super.getName()).iterator().next();
		String username = shiroUser.getAccount();
		try {
			if (username != null && !"".equals(username)) {
				SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
				List<String> perList = null;
				if (Constants.SYSTEM_USER.equals(username)) {
					perList = this.sysPermissionService.getSysIdByStatusAndType(Constants.PERSISTENCE_ENABLE_STATUS, "O"); 
				}
				else {
					perList = this.sysPermissionService.getSysIdByUserAccount(username, Constants.PERSISTENCE_ENABLE_STATUS, "O");
				}
				if (perList != null && !perList.isEmpty()) {
					info.addStringPermissions(perList);
					LogService.getInstance(this).debug(username + "获取授权信息成功...");
					return info;
				}
			}
		}
		catch(Exception ex) {
			LogService.getInstance(this).error(username + "获取授权信息失败：" + ex.getMessage(), ex);
		}
		return null;
	}

	/***
	 * 功能说明：更新用户授权信息缓存
	 * 修改说明：
	 * @author zhenglibing
	 * @date 2017-4-24 下午2:57:28
	 * @param principal
	 */
	public void clearCachedAuthorizationInfo(String principal) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, super.getName());
		super.clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 功能说明：清除所有用户授权信息缓存
	 * 修改说明：
	 * @author zhenglibing
	 * @date 2017-4-24 下午3:00:16
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = super.getAuthorizationCache();
		if (cache != null) {
			for (Object key : cache.keys()) {
				cache.remove(key);
			}
		}
	}
}
